#include "stm32f10x.h"
#include "usart2.h"
#include "usart3.h"
#include "led.h"
#include "utils.h"
#include "SysTick.h"
#include "string.h"
#include "sxnutils.h"

static char last_cmd[4] = {0, 0, 0, 0}; // Buffer to store the last command;

void KeyInit(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void GetKey(void)
{

  if (Bit_RESET == GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13))
  {
    DelayNuS(100000);
    if (Bit_RESET == GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13))
    {
      while (Bit_RESET == GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13))
      {
        ;
      }
      // RS485_SendByte_U2('B');
      // RS485_SendString_U2("I am B");
      // RS485_SendByte_U3(0X02);
      LED1(0);
      LED2(1);
    }
  }

  if (Bit_RESET == GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12))
  {
    DelayNuS(100000);
    if (Bit_RESET == GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12))
    {
      while (Bit_RESET == GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12))
      {
        ;
      }
      // RS485_SendByte_U2('A');
      // RS485_SendString_U2("I am A");
      // RS485_SendByte_U3(0X01);
      LED1(1);
      LED2(0);
    }
  }
}

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Configure the NVIC Preemption Priority Bits */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

  /* Enable the USART3 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable the USART2 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void ForwardCommand(uint8_t *cmd_buffer, int len)
{
  char packet_n[SXN_PACKET_LEN+1];
  #if FROM_TYPE == FROM_104T  // from 104T
  const char *cmd_run_104t = "$A9,RUN,";
  const char *cmd_stp_104t = "$A9,STP,";
  #elif FROM_TYPE == FROM_104N  // from 104N
  const char *cmd_run_104n = "$AM,RUN,";
  const char *cmd_stp_104n = "$AM,STP,";
  const char *cmd_req_104n = "$AM,REQ,";
  #endif

  cmd_buffer[len] = 0;

  if (0) {
    // Do nothing, this is a placeholder for future commands
  }
  #if FROM_TYPE == FROM_104T  // from 104T
  // If it's a 104T command, convert it to 104N and send to u2
  if (strncmp((const char *)cmd_buffer, cmd_run_104t, strlen(cmd_run_104t)) == 0 || strncmp((const char *)cmd_buffer, cmd_stp_104t, strlen(cmd_stp_104t)) == 0) {
    strncpy(last_cmd, (const char *)cmd_buffer+4, 3);
    #if TO_TYPE == TO_104N  // to 104N
    if (sxn_conv_cmd_104t_104n((const char *)cmd_buffer, packet_n)) {
      RS485_SendString_U2(packet_n);
    }
    #endif
    #if TO_TYPE == TO_154NH  // to 154NH
    if (sxn_conv_cmd_104t_154nh((const char *)cmd_buffer, packet_n)) {
      RS485_SendString_U2(packet_n);
    }
    #endif
  }
  #elif FROM_TYPE == FROM_104N  // from 104N
  // If it's a 104N command, convert it to 104T and send to u2
  if (strncmp((const char *)cmd_buffer, cmd_run_104n, strlen(cmd_run_104n)) == 0 || strncmp((const char *)cmd_buffer, cmd_stp_104n, strlen(cmd_stp_104n)) == 0 || strncmp((const char *)cmd_buffer, cmd_req_104n, strlen(cmd_req_104n)) == 0) {
    strncpy(last_cmd, (const char *)cmd_buffer+4, 3);
    #if TO_TYPE == TO_154NH  // to 154NH
    if (sxn_conv_cmd_104n_154nh((const char *)cmd_buffer, packet_n)) {
      RS485_SendString_U2(packet_n);
    }
    #endif
  } 
  #endif
  else {
    //Otherwise, send to u2 without change
    RS485_SendString_U2((const  char *)cmd_buffer);
  }
  // LED1(1);
  // LED2(1);
}

uint8_t cmd_buffer[RS485_RX_BUFFER_SIZE_U3];
void CheckReceivedCommand(void)
{
  static uint32_t timeout_tick = 0;
  int len;

  len = RS485_Get_Reveived_Data_U3(cmd_buffer, sizeof(cmd_buffer));
  if (len > 0) {
    if (cmd_buffer[0] == '$') {
      if (cmd_buffer[len-2] == '\r' && cmd_buffer[len-1] == '\n') {
        // Valid start and stop
        RS485_Reset_Buffer_U3();
        timeout_tick = 0;

        ForwardCommand(cmd_buffer, len);
      } else if (timeout_tick == 0) {
        // Middle of command for first time
        timeout_tick = GetSysTick() + TICKS_PER_SECOND;
      } else {
        // Middle of command for second or more time, check timeout
        if (GetSysTick() > timeout_tick) {
          RS485_Reset_Buffer_U3();
          timeout_tick = 0;
        }
      }
    } else {
      // Invalid command start
      RS485_Reset_Buffer_U3();
    }
  }
}

void ForwardResponse(uint8_t *resp_buffer, int len)
{
  char packet_n[MAX_SXN_RESP_PACKET_LEN+1];
  const char *rsp_req_154nh = "$Et,";

  if (0) {
    // Do nothing, this is a placeholder for future commands
  }
  #if TO_TYPE == TO_154NH  // to 154NH
  else if (strncmp((const char *)resp_buffer, rsp_req_154nh, strlen(rsp_req_154nh)) == 0) {
    #if FROM_TYPE == FROM_104N  // from 104N
    if (strncmp(last_cmd, "REQ", 3) == 0) {
      if (sxn_conv_rsp_req_154nh_104n((const char *)resp_buffer, packet_n)) {
        RS485_SendString_U3(packet_n);
      }
    }
    #endif
  }
  #endif
  else {
    //Otherwise, send to u3 without change
    RS485_SendString_U3((const  char *)resp_buffer);
  }
}


uint8_t resp_buffer[RS485_RX_BUFFER_SIZE_U2];
void CheckReceivedResponse(void)
{
  static uint32_t timeout_tick = 0;
  int len;

  len = RS485_Get_Reveived_Data_U2(resp_buffer, sizeof(resp_buffer));
  if (len > 0) {
    if (resp_buffer[0] == '$') {
      if (resp_buffer[len-2] == '\r' && resp_buffer[len-1] == '\n') {
        // Valid start and stop
        RS485_Reset_Buffer_U2();
        timeout_tick = 0;

        ForwardResponse(resp_buffer, len);
      } else if (timeout_tick == 0) {
        // Middle of command for first time
        timeout_tick = GetSysTick() + TICKS_PER_SECOND;
      } else {
        // Middle of command for second or more time, check timeout
        if (GetSysTick() > timeout_tick) {
          RS485_Reset_Buffer_U2();
          timeout_tick = 0;
        }
      }
    } else {
      // Invalid command start
      RS485_Reset_Buffer_U2();
    }
  }
}

int main(void)
{
  SystemInit();
  SysTick_Init();
  KeyInit();
  LED_GPIO_Config();
  NVIC_Configuration();
  USART2_init();
  USART3_init();

  while (1)
  {
    CheckReceivedCommand();
    CheckReceivedResponse();
    GetKey();
  }
  // while (1) {
  //   LED1( 0 ); 
  //   LED2( 0 );  
  //   DelayMs(500);    // 500 * 1ms = 500ms
  //   LED1( 1 );      
  //   LED2( 1 );     
  //   DelayMs(500);
  // }
}
